#!/usr/bin/env python
# -*- coding: utf-8 -*-

import difflib
import datetime

from farado.logger import logger
from farado.general_manager_holder import gm_holder
from farado.items.field_kind import ValueTypes
from farado.items.issue_change import IssueChange



class ChangesHelper():
    def __init__(self, user_id) -> None:
        self.following_data = None
        self.following_id = None
        self.user_id = user_id

    #--------------------------------------------------------------------------#
    def follow(self, item):
        self.following_data = self.history_data(item)
        self.following_id = item.id

    #--------------------------------------------------------------------------#
    def finalize(self, item):
        current_data = self.history_data(item)
        diff = self.make_diff(self.following_data, current_data)

        # При создании нового объекта отсутствует following_id.
        if not self.following_id:
            self.following_id = item.id

        change = self.save(diff)
        self.following_data = None
        self.following_id = None
        return change

    #--------------------------------------------------------------------------#
    def save(self, diff):
        pass

    #--------------------------------------------------------------------------#
    def history_data(self, issue):
        return {}

    #--------------------------------------------------------------------------#
    def make_diff(self, a, b):
        return {}

    #--------------------------------------------------------------------------#
    def _add_if_different_value(self, a, b, key, container):
        a_value, b_value = self._values_by_key(a, b, key)
        are_different, difference = self._text_diff(a_value, b_value)
        if are_different:
            container[key] = difference

    #--------------------------------------------------------------------------#
    def _add_if_different_dict(self, a, b, key, container):
        a_value, b_value = self._values_by_key(a, b, key, {}, {})
        result = {}
        for sub_key in {**a_value,  **b_value}.keys():
            self._add_if_different_value(a_value, b_value, sub_key, result)
        if len(result):
            container[key] = result

    #--------------------------------------------------------------------------#
    def _values_by_key(self, a, b, key, a_default='', b_default=''):
        a_value = a_default
        b_value = b_default
        if (key in a):
            a_value = a[key]
        if (key in b):
            b_value = b[key]
        return a_value, b_value

    #--------------------------------------------------------------------------#
    def _text_diff(self, a, b):
        if not a:
            a = ''
        if not b:
            b = ''
        a_data = a.splitlines(keepends=True)
        b_data = b.splitlines(keepends=True)
        if len(a_data):
            a_data[-1] += '\n'
        if len(b_data):
            b_data[-1] += '\n'
        return not(a == b), ''.join(difflib.ndiff(a_data, b_data))

class IssueChangesHelper(ChangesHelper):

    #--------------------------------------------------------------------------#
    def save(self, diff):
        if 0 == len(diff):
            return None

        issue_change = IssueChange(
            issue_id=self.following_id,
            dict_diff=diff,
            user_id=self.user_id
        )
        gm_holder.project_manager.save_item(issue_change)
        return issue_change

    #--------------------------------------------------------------------------#
    def history_data(self, item):
        result = {}
        if not item:
            return result

        result[IssueChange.DiffKey.caption] = f'#{item.id} {item.caption}'
        result[IssueChange.DiffKey.content] = item.content

        state = gm_holder.project_manager.state(item.state_id)
        if state:
            result[IssueChange.DiffKey.state] = {state.id: state.caption}

        project = gm_holder.project_manager.project(item.project_id)
        if project:
            result[IssueChange.DiffKey.project] = {project.id: project.caption}

        parent = gm_holder.project_manager.issue(item.parent_id)
        if parent:
            result[IssueChange.DiffKey.parent] = {
                parent.id: f'#{parent.id} {parent.caption}'
            }

        version = gm_holder.project_manager.version(item.version_id)
        if version:
            result[IssueChange.DiffKey.version] = {version.id: version.caption}

        result[IssueChange.DiffKey.files] = {}
        for file in item.files:
            result[IssueChange.DiffKey.files][file.id] = file.caption

        result[IssueChange.DiffKey.fields] = {}
        for field in item.fields:
            field_kind = gm_holder.project_manager.field_kind(field_kind_id=field.field_kind_id)
            if not field_kind:
                value = field.value

            elif ValueTypes.date_time == field_kind.value_type:
                # Дата/время
                value = field.value
                if field.value:
                    value = f'{datetime.datetime.fromisoformat(field.value):%d.%m.%Y %H:%M:%S}'

            elif ValueTypes.issue_id == field_kind.value_type:
                # Запрос (issue)
                issue = gm_holder.project_manager.issue(field.value)
                value = f'{issue.id} {issue.caption}' if issue else field.value

            elif ValueTypes.user_id == field_kind.value_type:
                # Пользователь
                user = gm_holder.project_manager.user(field.value)
                value = f'{user.last_name} {user.first_name}' if user else field.value

            elif ValueTypes.project_id == field_kind.value_type:
                # Проект
                project = gm_holder.project_manager.project(field.value)
                value = project.caption if project else field.value

            elif ValueTypes.version_id == field_kind.value_type:
                # Версия
                version = gm_holder.project_manager.version(field.value)
                value = version.caption if version else field.value

            elif ValueTypes.issues_ids == field_kind.value_type:
                # Перечень запросов (issue)
                values = []
                for id in field.value_as_ids():
                    issue = gm_holder.project_manager.issue(id)
                    values.append(
                        f'{issue.id} {issue.caption}' if issue else str(id)
                    )
                value = ', '.join(values)

            elif ValueTypes.users_ids == field_kind.value_type:
                # Перечень пользователей
                values = []
                for id in field.value_as_ids():
                    user = gm_holder.project_manager.user(id)
                    values.append(f'{user.last_name} {user.first_name}' if user else str(id))
                value = ', '.join(values)

            elif ValueTypes.projects_ids == field_kind.value_type:
                # Перечень проектов
                values = []
                for id in field.value_as_ids():
                    project = gm_holder.project_manager.project(id)
                    values.append(project.caption if project else str(id))
                value = ', '.join(values)

            elif ValueTypes.versions_ids == field_kind.value_type:
                # Перечень версий
                values = []
                for id in field.value_as_ids():
                    version = gm_holder.project_manager.version(id)
                    values.append(version.caption if version else str(id))
                value = ', '.join(values)

            else:
                value = field.value

            result[IssueChange.DiffKey.fields][field.field_kind_id] = value

        result[IssueChange.DiffKey.comments] = {}
        for comment in item.comments:
            result[IssueChange.DiffKey.comments][comment.id] = comment.content
            for file in comment.files:
                result[IssueChange.DiffKey.files][file.id] = file.caption

        return result

    #--------------------------------------------------------------------------#
    def make_diff(self, a, b):
        result = {}
        self._add_if_different_value(a, b, IssueChange.DiffKey.caption, result)
        self._add_if_different_value(a, b, IssueChange.DiffKey.content, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.state, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.project, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.parent, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.version, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.files, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.fields, result)
        self._add_if_different_dict(a, b, IssueChange.DiffKey.comments, result)
        return result
